package com.leenmvc.core.config.filter;

import cn.hutool.core.io.FileUtil;
import com.leenmvc.core.base.BaseEntity;
import com.leenmvc.core.base.EntityInfo;
import com.leenmvc.core.base.result.ResultCode;
import com.leenmvc.core.cache.CacheFactory;
import com.leenmvc.core.enums.CacheType;
import com.leenmvc.core.enums.EntityInfoEnum;
import com.leenmvc.core.init.Constant;
import com.leenmvc.core.security.User;
import com.leenmvc.core.security.dao.core.SysPermissionDao;
import com.leenmvc.core.security.entity.core.SysPermission;
import com.leenmvc.core.utils.ClassUtil;
import com.leenmvc.core.utils.TipUtil;
import com.leenmvc.core.utils.http.HttpContextUtils;
import com.leenmvc.core.utils.http.RequestParameterWrapper;
import com.leenmvc.core.utils.http.entity.UrlData;
import com.leenmvc.core.utils.spring.SpringContextUtils;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.NestedServletException;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 全局过滤器
 */
@WebFilter(filterName = "myFilter", urlPatterns = "/*", initParams = @WebInitParam(name = "excludedPaths", value = "*.js"))
public class GlobalFilter implements Filter {

    private final static Logger logger = LoggerFactory.getLogger(GlobalFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponseWrapper httpResponse = new HttpServletResponseWrapper((HttpServletResponse) response);
        String path = httpRequest.getRequestURI();
        try {
            // 根据 url 转向

            logger.info("本次请求的请求地址是：{}", path);
            // 设置实际url本地变量(只能在这里设置，在过滤器中设置那么永远都会是公共方法)
            ThreadLocalManager.put(Constant.CONTROLLER_URI, path);
            ThreadLocalManager.put("contentType", request.getContentType());
            // 删除
            String method = httpRequest.getMethod();
            if("/".equals(path)) {
                httpRequest.getRequestDispatcher("/system/common/view/index").forward(getRequestParameterWrapper(httpRequest, "/system/common/view/index"), response);
                return;
            }

            if(path.endsWith(".html")) {
                logger.info("当前请求的路径是：{}", path);
                path = path.replace(".html", "");
//                String viewPath = Constant.COMMON_URL_BASE_VIEW + path;
//                httpRequest.getRequestDispatcher(viewPath).forward(getRequestParameterWrapper(httpRequest, viewPath), response);

                String html = FileUtil.readString(Constant.WORK_DIR + "/html-model/sysRole.html", "utf-8");
                String[] pathArr = path.split("/");
                String key = pathArr[pathArr.length - 1];
                EntityInfo entityInfo = BaseEntity.entityMap.get(key);
                if(entityInfo != null) {
                    String[] fieldStrArr = entityInfo.getFieldStrArr(EntityInfoEnum.FIELDS);
                    StringBuilder htmlfields = new StringBuilder();
                    for(String field: fieldStrArr) {
                        // result.data.data[d].id + result.data.data[d].username
                        htmlfields.append("<td>").append(field).append("</td>");
                    }

                    html = html.replace("【TABLE-TITLE】", htmlfields);
                    htmlfields.setLength(0);
                    for(String field: fieldStrArr) {
//                        "<td>" + result.data.data[d].id + "</td><td>" + result.data.data[d].name</td><td>result.data.data[d].module</td><td>result.data.data[d].uri</td><td>result.data.data[d].identification</td>"
                        htmlfields.append("<td>\" + result.data.data[d].").append(field).append("+\"</td>");
                    }
                    html = html.replace("【TABLE-TR】", htmlfields);
                    html = html.replace("【ENTITY】", key);
                }

                HttpContextUtils.returnHtml(httpResponse, html);
                return;
            }

            String[] pathArr = path.split("/");
            if (BaseEntity.entityMap.get(pathArr[pathArr.length - 1]) != null) {
                EntityInfo entity = BaseEntity.entityMap.get(pathArr[pathArr.length - 1]);
                String tableComment = ClassUtil.getTableComment(entity.getRealClass());
                ThreadLocalManager.put("module", tableComment);
                if ("delete".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "del", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的删除操作；实际对象url为：{}", path);
                    ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "根据ID数组删除" + tableComment);
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                } else if ("post".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "save", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的保存操作；实际对象url为：", path);
                    ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "新增" + tableComment + "记录");
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                } else if ("put".equalsIgnoreCase(method)) {
                    authentication(httpRequest, httpResponse, pathArr, "update", 1);
                    logger.info("过滤器执行转发转发地址为/system/common/的更新操作；实际对象url为：", path);
                    ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "修改" + tableComment + "记录");
                    httpRequest.getRequestDispatcher("/system/common").forward(getRequestParameterWrapper(httpRequest, path), response);
                    return;
                }
            }
            EntityInfo entityInfo = BaseEntity.entityMap.get(pathArr[pathArr.length - 2]);
            String tableComment = "";
            if (entityInfo != null) {
                tableComment = ClassUtil.getTableComment(entityInfo.getRealClass());
                ThreadLocalManager.put("module", tableComment);
            }

            if (path.endsWith(Constant.COMMON_URL_PAGE)) {
                authentication(httpRequest, httpResponse, pathArr, "page", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "分页获取" + tableComment + "记录");
                logger.info("【公用获取分页记录方法】过滤器执行转发转发地址为/system/common/page");
                httpRequest.getRequestDispatcher("/system/common/page").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith(Constant.COMMON_URL_SQL_PAGE)) {
                authentication(httpRequest, httpResponse, pathArr, "sqlPage", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "分页获取" + tableComment + "记录（手写SQL语句）");
                logger.info("【公用获取分页记录方法】过滤器执行转发转发地址为/system/common/sqlPage");
                httpRequest.getRequestDispatcher("/system/common/sqlPage").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith(Constant.COMMON_URL_SQLKVS)) {
                authentication(httpRequest, httpResponse, pathArr, "sqlKvs", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "获取" + tableComment + "的KVs键值对记录(手写SQL)");
                logger.info("【公用获取KVS手写SQL记录方法】过滤器执行转发转发地址为/system/common/sqlKvs");
                httpRequest.getRequestDispatcher("/system/common/sqlKvs").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith(Constant.COMMON_URL_KVS)) {
                authentication(httpRequest, httpResponse, pathArr, "kvs", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "获取" + tableComment + "的KVs键值对记录");
                logger.info("【公用获取KVS记录方法】过滤器执行转发转发地址为/system/common/kvs");
                httpRequest.getRequestDispatcher("/system/common/kvs").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith(Constant.COMMON_URL_GETBYID)) {
                authentication(httpRequest, httpResponse, pathArr, "getById", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "根据ID获取" + tableComment + "记录");
                logger.info("【公用根据ID获取单条记录方法】过滤器执行转发转发地址为/system/common/getById");
                httpRequest.getRequestDispatcher("/system/common/getById").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            }  else if (path.endsWith("/getList")) {
                authentication(httpRequest, httpResponse, pathArr, "getList", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "根据ID获取" + tableComment + "记录");
                logger.info("【公用获取列表】过滤器执行转发转发地址为/system/common/getList");
                httpRequest.getRequestDispatcher("/system/common/getList").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if (path.endsWith("/getAll")) {
                authentication(httpRequest, httpResponse, pathArr, "getAll", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "根据ID获取" + tableComment + "记录");
                logger.info("【公用获取全部记录】过滤器执行转发转发地址为/system/common/getAll");
                httpRequest.getRequestDispatcher("/system/common/getAll").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            } else if(path.endsWith("/simpleExport")) {
                authentication(httpRequest, httpResponse, pathArr, "export", 2);
                ThreadLocalManager.put(Constant.CONTROLLER_NOTE, "导出数据表为Excel表格（" + tableComment + ")");
                logger.info("【公用方法导出】过滤器执行转发转发地址为/system/common/export");
                httpRequest.getRequestDispatcher("/system/common/export").forward(getRequestParameterWrapper(httpRequest, path), response);
                return;
            }
            else {
                logger.info("过滤器正式执行过滤通过操作，通过路径为：{}, 该请求携带的参数为：{}", path, HttpContextUtils.getParameterMap(httpRequest));
                UrlData urlData = CacheFactory.get(CacheType.URL_INFO, path);
                if(urlData == null && path.indexOf(".") == -1) { // 拦截数据接口请求
                    HttpContextUtils.returnCodePage(httpRequest, httpResponse, ResultCode.NOT_FOUND);
                    return;
                }
                ThreadLocalManager.put("module", urlData == null ? "未指定模块" : urlData.getModule());
                chain.doFilter(request, response);
                return;
            }
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } catch (NestedServletException e) {
            logger.error(e.getMessage(), e);
            logger.warn("寻找thymeleaf模板的时候发生错误，使用默认模板。。。");
            HttpContextUtils.returnCodePage(httpRequest, httpResponse, ResultCode.NOT_FOUND);
            return;
        } catch (ServletException e) {
            logger.error(e.getMessage(), e);
        }catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 公共方法鉴权
     *
     * @param pathArr
     */
    private void authentication(HttpServletRequest httpRequest, HttpServletResponseWrapper httpResponse, String[] pathArr, String authentication, int index) {
        if(Constant.dev_mode) return;
        Integer superAdmin = User.getSuperAdmin();
        logger.info("当前用户是否为超级管理员对象: {}" , superAdmin);
        if(superAdmin != null && superAdmin == 1) {
            return;
        }

        Set<String> permisions = User.getPermisions();
        String auth = pathArr[pathArr.length - (index + 1)] + ":" + pathArr[pathArr.length - index] + ":" + authentication;
        if (!permisions.contains(auth)) {
            SysPermissionDao sysPermissionDao = SpringContextUtils.getBean(SysPermissionDao.class);
            SysPermission perm = sysPermissionDao.get("identification", auth);
            if (perm == null) {
                HttpContextUtils.returnJSON(httpRequest, httpResponse, TipUtil.getTip("EXCEPTION_POWER_NOT_OPEN", auth));
                return;
            }
            HttpContextUtils.returnJSON(httpRequest, httpResponse, TipUtil.getTip("EXCEPTION_NO_POWER", perm.getModule(), perm.getName(), perm.getIdentification()));
        }
    }

    public static RequestParameterWrapper getRequestParameterWrapper(HttpServletRequest httpRequest, String path) {
        Map<String, Object> otherParams = new HashMap<>();
        otherParams.put("url", path);
        RequestParameterWrapper requestParameterWrapper = new RequestParameterWrapper(httpRequest);
        requestParameterWrapper.addParameters(otherParams);
        ThreadLocalManager.put("request_url", path);
        return requestParameterWrapper;
    }

    @Override
    public void destroy() {
    }
}
